package eu.sudparis.it.opp.ex;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import eu.sudparis.it.opp.Node;
import eu.sudparis.it.opp.demo.DNode;

public class SocialTags {
	public HashMap<String, List<Integer>> profile = new HashMap<String, List<Integer>>();
	public final static int user = 0;
	public final static int external_device=1;
	public final static int static_station = 2;
	public final static int community = 3;
	public int status = 0;

	public static boolean isNumeric(String str) {
		for (int i = str.length(); --i >= 0;) {
			if (!Character.isDigit(str.charAt(i))) {
				return false;
			}
		}
		return true;
	}
	public SocialTags() {}
	public SocialTags(File re) {
		try {
			if (!re.exists()) {
				this.status=external_device;
				return;
			}
			BufferedReader br = new BufferedReader(new InputStreamReader(
					new FileInputStream(re)));
			String ln = br.readLine();
			while (ln != null && ln.length() != 0) {
				String[] plin = ln.split("=");
				List<Integer> ins = new ArrayList<Integer>();
				if (plin.length > 1) {
					String[] ints = plin[1].split(",");
					for (String intt : ints) {
						if (isNumeric(intt))
							ins.add(Integer.parseInt(intt));
					}
				}
				profile.put(plin[0], ins);
				ln = br.readLine();
			}
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public double cosineSimilarityWith(SocialTags p, String colum) {
		List<Integer> thiss = this.profile.get(colum);
		List<Integer> ints = p.profile.get(colum);
		if (thiss==null||ints==null||thiss.size() == 0 || ints.size() == 0)
			return 0;
		double cos = 0;
		for (int ts : thiss) {
			if (ints.contains(ts))
				cos++;
		}
		return cos / (Math.sqrt(thiss.size()) * Math.sqrt(ints.size()));
	}

	public double distanceBetween(SocialTags p, String colum) {
		List<Integer> thiss = this.profile.get(colum);
		List<Integer> ints = p.profile.get(colum);
		double cos = 0;
		for (int ts : thiss) {
			if (!ints.contains(ts))
				cos++;
		}
		for (int ts : ints) {
			if (!thiss.contains(ts))
				cos++;
		}
		return cos;
	}

	public boolean has(String attr, int val) {
		if (!this.profile.containsKey(attr))
			return false;
		return this.profile.get(attr).contains(val);
	}

	public static double minimalEntropy(HashMap<Integer, Integer> map,
			double size) {
		double sum = map.keySet().size();
		double res = 1;
		if (sum == 0)
			return res;
		for (double each : map.values()) {
			double result = 0;
			if (each != 0 && each != size)
				result = -each / size * Math.log(each / size) - (size - each)
						/ size * Math.log((size - each) / size);
			else {
				result = 0;
			}
			if (result < res)
				res = result;
		}
		return res
				/ (-1 / size * Math.log(1 / size) - (size - 1) / size
						* Math.log((size - 1) / size));
	}

	public static HashMap<Integer, Integer> entropyEstimation(List<Node> ndset,
			String attr) {
		HashMap<Integer, Integer> result = new HashMap<Integer, Integer>();
		List<SocialTags> prfs = new ArrayList<SocialTags>();
		Set<Integer> sets = new HashSet<Integer>();
		for (Node nd : ndset) {
			SocialTags prof = ((DNode) (nd.chain_of_responsibility)).self;
			prfs.add(prof);
			if (prof.profile.containsKey(attr)) {
				sets.addAll(prof.profile.get(attr));
			}
		}
		// sets.add(-1);
		for (int val : sets) {
			result.put(val, counting(prfs, attr, val));
		}
		return result;

	}

	public static int counting(List<SocialTags> ndset, String attr, int val) {
		int postive = 0;
		for (SocialTags nod : ndset) {
			if (val != -1 && nod.has(attr, val)) {
				postive++;
			} else if (val == -1 && nod.profile.containsKey(attr)
					&& nod.profile.get(attr).size() == 0) {
				postive++;
			}
		}
		return postive;
	}

	public List<Integer> insectionWith(SocialTags p, String colum) {
		List<Integer> result = new ArrayList<Integer>();
		for (Integer val : p.profile.get(colum)) {
			if (this.has(colum, val) && !result.contains(val))
				result.add(val);
		}
		for (Integer val : this.profile.get(colum)) {
			if (p.has(colum, val) && !result.contains(val))
				result.add(val);
		}
		return result;
	}
}
